#include "./ChildCreationRequestListener.h"

DlmComm* ChildCreationRequestListener::communicationModule = NULL;

/**
 * Default constructor.
 */
ChildCreationRequestListener::ChildCreationRequestListener()
{
    fifoName = new std::string("/tmp/dlm-fifo");

    action.sa_handler = sigchldHandler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGCHLD, &action, NULL);
}

/**
 * Copy constructor.
 */
ChildCreationRequestListener::ChildCreationRequestListener(DlmComm* communicationModule, int dlm_pipe, int info_pipe)
{
	fifoName = new std::string("/tmp/dlm-fifo");;
	this->dlm_pipe = dlm_pipe;
	this->info_pipe = info_pipe;
	this->communicationModule = communicationModule;

	action.sa_handler = sigchldHandler;
	sigemptyset(&action.sa_mask);
	action.sa_flags = 0;
	sigaction(SIGCHLD, &action, NULL);
}

/**
 * Destructor.
 */
ChildCreationRequestListener::~ChildCreationRequestListener()
{
    delete fifoName;
    remove(fifoName->c_str());
}

/**
 * Method used to initialize the object by creating a FIFO and opening it's symbolic link.
 */
void ChildCreationRequestListener::initializeFifo()
{
    int result;

    if (!((result = mkfifo(fifoName->c_str(), S_IRUSR | S_IWUSR)) == 0 || errno == EEXIST))
            throw FifoException("[CHILD_CREATION_MODULE] Cannot create a FIFO!");
}

/**
 * Method used to listen for requests of new processes creation.
 */
void* ChildCreationRequestListener::listen()
{
    int size;
    pid_t pid;
    int back_info[2];

	/* Read data from FIFO and create child processes */
	while (true)
	{
		/* Try to open the FIFO */
		if ((fifoDescriptor = TEMP_FAILURE_RETRY(open(fifoName->c_str(), O_RDONLY))) < 0)
		{
			std::cout << errno << std::endl;
            throw FifoException("[CHILD_CREATION_MODULE] Cannot open a FIFO!");
		}
		if ((size = read(fifoDescriptor, readBuffer, sizeof(readBuffer))) >= 0)
		{
			pipe(back_info);
			readBuffer[size] = '\0';
			Logger::getInstance().logDlm(Logger::INFO, "[CHILD_CREATION_MODULE] Read from FIFO: '%s'", readBuffer);
			if ((pid = fork()) == 0)
			{
				Logger::getInstance().logDlm(Logger::INFO, "[CHILD_CREATION_MODULE] Process forked.");
				if (back_info[0] != STDIN_FILENO)
				{
					if (dup2(back_info[0], STDIN_FILENO) < 0)
						Logger::getInstance().logDlm(Logger::ERRNO, "[CHILD_CREATION_MODULE] Cannot redirect process' stdin.");
					close(back_info[0]);
				}
				if (dlm_pipe != STDOUT_FILENO)
				{
					if (dup2(dlm_pipe, STDOUT_FILENO) < 0)
						Logger::getInstance().logDlm(Logger::ERRNO, "[CHILD_CREATION_MODULE] Cannot redirect process' stdout.");
				}
				if (info_pipe != STDERR_FILENO)
				{
					if (dup2(info_pipe, STDERR_FILENO) < 0)
						Logger::getInstance().logDlm(Logger::ERRNO, "[CHILD_CREATION_MODULE] Cannot redirect process' stderr.");
				}
				if (execl(readBuffer, readBuffer, NULL) < 0)
				{
					Logger::getInstance().logDlm(Logger::ERRNO, "[CHILD_CREATION_MODULE] Cannot execute %s", readBuffer);
					exit(1);
				}
			} else
			{
				communicationModule->clientRegister(pid, back_info[1]);
			}
		} else if (size == 0)
		{
				close(fifoDescriptor);
				continue;
		}
		else
			Logger::getInstance().logDlm(Logger::ERRNO, "[CHILD_CREATION_MODULE] Error while reading from fifo.");		
	}

    return NULL;
}
